use super::*;
use wasm_bindgen::JsCast;
use web_sys::HtmlDocument;
use y_math::verify;

#[wasm_bindgen]
pub struct YnCookie {
    html_document: HtmlDocument,
}

#[wasm_bindgen]
impl YnCookie {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Self {
        let window = web_sys::window().unwrap();
        let document = window.document().unwrap();
        let html_document = document.dyn_into::<web_sys::HtmlDocument>().unwrap();
        Self { html_document }
    }

    /// 设置 非加密 cookie
    /// 如需要加密数据请使用 [`YnCookie.set_encrypt`] 方法
    #[allow(dead_code)]
    pub fn set(&self, key: String, value: String, expire: Option<i32>) -> bool {
        let mut value = format!("{}={}", &key, &value);
        if let Some(e) = expire {
            let expire = date_time::set_timestamp_string(e);
            value = format!("{}; expires={:?}", value, expire);
        }
        match self.html_document.set_cookie(&value) {
            Ok(_) => {
                return true;
            }
            Err(e) => {
                error(&format!("存储cookie失败,错误:{:?}", e));
                return false;
            }
        }
    }

    /// 设置 加密 cookie
    /// 如需获取解密值请使用 [`YnCookie.setEncrypt`] 方法 或 使用 [`decrypt`] 方法进行解密操作
    #[allow(dead_code)]
    #[wasm_bindgen(js_name = "setEncrypt")]
    pub fn set_encrypt(&self, key: String, value: String, expire: Option<i32>) {
        let value = verify::encrypt(value);
        self.set(key, value, expire);
    }

    /// 根据key获取 cookie 数据值
    /// 如数据加密可以使用 [`decrypt`] 方法进行解密操作
    #[allow(dead_code)]
    pub fn get(&self, key: String) -> JsValue {
        self.get_value(key, false)
    }

    /// 根据key获取解密后的数据值
    #[allow(dead_code)]
    #[wasm_bindgen(js_name = "getDecrypt")]
    pub fn get_decrypt(&self, key: String) -> JsValue {
        self.get_value(key, true)
    }

    #[allow(dead_code)]
    fn get_value(&self, key: String, is_encrypt: bool) -> JsValue {
        match self.get_value2_vec() {
            Some(value) => {
                let values: Vec<String> = value.into_iter().filter(|x| x.contains(&key)).collect();
                for k in values {
                    match k.rsplit_once('=') {
                        Some((k, v)) => {
                            if key.eq(k) {
                                if is_encrypt {
                                    let v = verify::decrypt(v.to_owned());
                                    return JsValue::from_str(&v);
                                } else {
                                    return JsValue::from_str(v);
                                }
                            }
                        }
                        None => {}
                    }
                }
                JsValue::NULL
            }
            None => JsValue::UNDEFINED,
        }
    }

    #[allow(dead_code)]
    #[inline]
    fn get_value2_vec(&self) -> Option<Vec<String>> {
        match self.html_document.cookie() {
            Ok(value) => {
                let values = value.split("; ").map(|x| x.to_string()).collect();
                Some(values)
            }
            Err(e) => {
                error(&format!("查询cookie失败,错误:{:?}", e));
                None
            }
        }
    }

    /// 删除数据
    #[allow(dead_code)]
    pub fn remove(&self, key: String) -> bool {
        self.set(key, String::new(), Some(-10))
    }

    /// 清空cookie
    #[allow(dead_code)]
    pub fn clear(&self) -> bool {
        match self.get_value2_vec() {
            Some(value) => {
                for key in value {
                    match key.rsplit_once('=') {
                        Some((key, _v)) => {
                            self.set(key.to_string(), String::new(), Some(-10));
                        }
                        None => {}
                    };
                }
                true
            }
            None => true,
        }
    }
}
